package com.xcity.game.skill.template;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.xcity.game.combat.buff.CombatBuffTemplate;

import naga.x.game.template.Template;
import naga.x.game.template.TemplateException;
import naga.x.game.template.annotation.Binding;
import naga.x.game.template.annotation.Excel;
import naga.x.util.NumberUtils;
import naga.x.util.StringUtils;

@Excel(value = "skill.xlsx", sheet = 0)
public class SkillTemplate extends Template {

	/** 技能类型(0:被动,1:主动) */
	protected byte type;
	
	/** 拥有者（0：任何对象，1：主角，2：员工） */
	protected byte owner;
	
	/** 最高等级 */
	protected int maxLevel;
	
	/** 技能组(效果相同数值不同的技能为一组) */
	protected byte group;
	
	/** 技能cd(秒) */
	protected int cd;
	
	/** 技能名 */
	protected String name;
	
	/** 耗蓝 */
	protected int mp;
	
	/** 技能图标 */
	protected String icon;
	
	/** 技能描述（大括号表示具体数值，格式：{数值序号（从0开始）=初始数值#成长值}） */
	/** buff图标 */
	protected String buff;
	protected CombatBuffTemplate[] combatBuffs;
	
	/** 技能描述 */
	protected String desc;
	/** 数值 */
	protected List<Param> params;
	
	protected boolean canLevelUp;
	
//	protected PlayerSkillLevelUpTemplate levelUpTemplate;
	
	/** 升级表id */
	protected int upLvlId;
	protected List<SkillLevelUpTemplate> upLvlTemplates;
	
	public static final byte TYPE_PASSIVE = 0, // 被动
							 TYPE_ACTIVE = 1, // 主动
							 TYPE_COMBINE = 3; // 羁绊技能
	private int upLvlOffset; // 升级表起始偏移
	
	public static class Param {
		public final float initVal;
		public final float growthVal;
		public Param(float initVal, float growthVal) {
			this.initVal = initVal;
			this.growthVal = growthVal;
		}
	}
	
	public byte getType() {
		return type;
	}

	public void setType(byte type) {
		this.type = type;
	}

	public byte getOwner() {
		return owner;
	}

	public void setOwner(byte owner) {
		this.owner = owner;
	}

	public int getMaxLevel() {
		return maxLevel;
	}

	public void setMaxLevel(int maxLevel) {
		this.maxLevel = maxLevel;
	}

	public byte getGroup() {
		return group;
	}

	public void setGroup(byte group) {
		this.group = group;
	}

	public int getCd() {
		return cd;
	}

	public void setCd(int cd) {
		this.cd = cd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMp() {
		return mp;
	}

	public void setMp(int mp) {
		this.mp = mp;
	}

	public String getIcon() {
		return icon;
	}

	public void setIcon(String icon) {
		this.icon = icon;
	}

//	public String getBuff() {
//		return buff;
//	}

	public void setBuff(String buff) {
		this.buff = buff;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}
	
	public int getUpLvlId() {
		return upLvlId;
	}

	public void setUpLvlId(int upLvlId) {
		this.upLvlId = upLvlId;
	}

//	public SkillLevelUpTemplate getUpLvlTemplate() {
//		return upLvlTemplate != null || upLvlId == 0 ? upLvlTemplate : (upLvlTemplate = App.getApp().getServiceManager().get(TemplateService.class).get(SkillLevelUpTemplate.class, upLvlId));
//	}

	public List<SkillLevelUpTemplate> getUpLvlTemplates() {
		return upLvlTemplates;
	}

	@Binding(field = "upLvlId", ref = "id", type = SkillLevelUpTemplate.class)
	public void setUpLvlTemplates(List<SkillLevelUpTemplate> upLvlTemplates) {
		this.upLvlTemplates = upLvlTemplates;
	}

	public SkillLevelUpTemplate getUpLvlTemplate(int level) {
		int index = level - upLvlOffset;
		return index >= 0 && index < upLvlTemplates.size() ? upLvlTemplates.get(index) : null;
	}
	
	public List<Param> getParams() {
		return params;
	}

	public void setParams(List<Param> params) {
		this.params = params;
	}

	public Param getParam(int index) {
		return index >= 0 && index < params.size() ? params.get(index) : null;
	}
	
	public float getInitVal(int index) {
		Param p = getParam(index);
		return p != null ? p.initVal : 0f;
	}
	
	public float getValue(int index, int level) {
		if (level < 1) {
			return 0f;
		}
		Param p = getParam(index);
		return p != null ? p.initVal + (level - 1) * p.growthVal : 0f;
	}
	
	public float getGrowthVal(int index) {
		Param p = getParam(index);
		return p != null ? p.growthVal : 0f;
	}
	
	private Float[] initValsCache;
	public Float[] getInitVals() {
		if (initValsCache == null) {
			int size = params.size();
			Float[] vals = new Float[size];
			for (int i = 0; i < size; i++) {
				vals[i] = params.get(i).initVal;
			}
			initValsCache = vals;
		}
		return canLevelUp ? Arrays.copyOf(initValsCache, initValsCache.length) : initValsCache;
	}
	
	public Float[] getValues(int level) {
		if (level <= 1) {
			return getInitVals();
		}
		int size = params.size();
		Float[] vals = new Float[size];
		for (int i = 0; i < size; i++) {
			Param p = params.get(i);
			vals[i] = p.initVal + (level - 1) * p.growthVal;
		}
		return vals;
	}
	
	public boolean isCanLevelUp() {
		return canLevelUp;
	}
	
	// TODO
	public boolean isCombatSkill() {
		return id >= 90083 || (id >= 90041 && id <= 90045);
	}
	
	public CombatBuffTemplate getCombatBuff() {
		return getCombatBuff(0);
	}
	
	public CombatBuffTemplate getCombatBuff(int index) {
		return combatBuffs != null && index >= 0 && index < combatBuffs.length ? combatBuffs[index] : null;
	}
	
//	public PlayerSkillLevelUpTemplate getLevelUpTemplate() {
//		return levelUpTemplate;
//	}
//
//	@Binding(type = PlayerSkillLevelUpTemplate.class, field = "id", ref = "id")
//	public void setLevelUpTemplate(PlayerSkillLevelUpTemplate levelUpTemplates) {
//		this.levelUpTemplate = levelUpTemplates;
//	}
//	
//	public int getNeedExp(int level) {
//		PlayerSkillLevelUpTemplate ref = getLevelUpTemplate();
//		return ref != null ? ref.getTotalTime(level) : Integer.MAX_VALUE;
//	}
//	
//	public int ofLevel(int exp) {
//		PlayerSkillLevelUpTemplate ref = getLevelUpTemplate();
//		int[] exps = ref.times;
//		for (int i = 0; i < exps.length; i++) {
//			if (exp < exps[i]) {
//				return i;
//			}
//		}
//		return exps.length;
//	}

	@Override
	public void validate() throws TemplateException {
		Pattern p = Pattern.compile("\\{[^{}]+\\}");
		Matcher m = p.matcher(desc); // eg. 员工攻击建筑时，{0=20#1}%几率增加自己{1=10#1}%的综合能力
		StringBuffer buf = new StringBuffer();
		Map<Integer, Param> paramsMap = new TreeMap<Integer, Param>();
		while (m.find()) {
			String v = m.group();
			v = v.substring(1, v.length() - 1);
			int dot = v.indexOf('=');
			int index = NumberUtils.parseInt(v.substring(0, dot));
			v = v.substring(dot + 1);
			dot = v.indexOf('#');
			String[] paramsArr = StringUtils.split(v, "#");
			float initVal = 0f, growthVal = 0f;
			if (paramsArr.length > 0) initVal = NumberUtils.parseFloat(paramsArr[0]);
			if (paramsArr.length > 1) growthVal = NumberUtils.parseFloat(paramsArr[1]);
			paramsMap.put(index, new Param(initVal, growthVal));
			if (growthVal > 0) {
				canLevelUp = true;
			}
			
			if (paramsArr.length > 2) {
				m.appendReplacement(buf, paramsArr[2]);
			} else {
				m.appendReplacement(buf, "{" + index + "}");
			}
		}
		m.appendTail(buf);
		desc = buf.toString().intern();
		params = paramsMap.isEmpty() ? Collections.emptyList() : new ArrayList<Param>(paramsMap.values());
		
		// buff icon
		if (StringUtils.isNotEmpty(buff)) {
			buff = buff.trim();
			String[] ss = StringUtils.split(buff, ",");
			combatBuffs = new CombatBuffTemplate[ss.length];
			for (int i = 0; i < ss.length; i++) {
				CombatBuffTemplate cbt = CombatBuffTemplate.create(ss[i]);
				combatBuffs[i] = cbt;
			}
			buff = null;
		}
		
		upLvlOffset = getUpLvlTemplates().get(0).getLevel();
	}

}
